﻿using System;
using System.Linq;
using Crossroad.Core.Exceptions;
using Crossroad.OAuth.Service;
using Crossroad.OAuth.Service.Impl;
using Crossroad.Utils.Extensions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Crossroad.OAuth.Attributes
{
    /// <summary>
    /// api接口的身份验证
    /// </summary>
    public sealed class ApiAuthorizeAttribute : ActionFilterAttribute
    {
        private readonly IAccessTokenService accessTokenService = new AccessTokenService();

        /// <summary>
        /// 认证是否启用 默认：true=启用
        /// </summary>
        public bool Enable { set; get; } = true;

        public ApiAuthorizeAttribute()
        {
        }

        /// <inheritdoc />
        /// <summary>
        /// 构造方法 
        /// </summary>
        /// <param name="enable">是否启用验证</param>
        public ApiAuthorizeAttribute(bool enable)
        {
            Enable = enable;
        }

        /// <summary>
        /// 在调用操作方法之前发生
        /// </summary>
        /// <param name="actionContext">操作上下文</param>
        public override void OnActionExecuting(ActionExecutingContext actionContext)
        {
            var context = actionContext.HttpContext;
            //获取当前请求方法 标注的api访问令牌注解对象
             var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
            var apiAuthorize = (ApiAuthorizeAttribute)actionDescriptor.MethodInfo.GetCustomAttributes(typeof(ApiAuthorizeAttribute), false).FirstOrDefault();
            if(apiAuthorize.IsNull())
                apiAuthorize = (ApiAuthorizeAttribute)actionDescriptor.ControllerTypeInfo.GetCustomAttributes(typeof(ApiAuthorizeAttribute), false).FirstOrDefault();
            //如果 访问令牌注解 Enable == false 则不验证 访问令牌
            if (apiAuthorize.IsNull() || (apiAuthorize.NotNull() && !apiAuthorize.Enable))
                return;

            var authorizeValue = context.Request.Headers
                .FirstOrDefault(m => m.Key.Equals("Authorization")).Value.FirstOrDefault();

            if (authorizeValue.IsNullOrEmpty())
                //失败请求处理
                throw new AuthorizeException("身份验证失败，未能找到访问令牌！");

            var token = accessTokenService.GetEntity(query =>
                query.Where(
                    a => a.accessToken.Equals(authorizeValue) 
                        && a.expires > DateTime.Now.ToTimeStamp()
                )
            );
            if (token.IsNull())
                //失败请求处理
                throw new AuthorizeException("身份验证失败，查无此访问令牌！");
        }


    }
}
